package com.zx.process;

import java.lang.reflect.Field;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zx.annotation.ColumnConfig;
import com.zx.annotation.DataConfig;
import com.zx.exception.DataParseException;

/**
 * @Project: dataParse
 * @Title: DataConfigProcess
 * @Description: 文件解析抽象类
 * @author: zhangxue
 * @date: 2017年11月18日下午3:18:45
 * @version v1.0
 */
abstract public class DataConfigProcess<T> {
	
	private static Logger logger = LoggerFactory.getLogger(DataConfigProcess.class);
	
	/** 写有注解的目标类 */
	private Class<T> clazz;
	
	/** 目标类的注解对象 */
	private DataConfig dataConfig;
	
	/* ***********************  1. abstract method    *********************************************/
	/**
	 * @Title: 解析一行数据
	 * @param str			一行数据
	 * @return
	 * @throws Exception 
	 * @date: 2017年11月18日下午3:07:12
	 */
	public abstract T parse(String str) throws DataParseException;
	
	/**
	 * @Title: 解析一行数据返回一个集合	
	 * @param str
	 * @return	
	 * @throws DataParseException
	 * @author: xue.zhang
	 * @date 2018年2月12日下午4:09:44
	 */
	public abstract List<T> parseList(String str) throws DataParseException;
	
	/**
	 * @Title: 解析多行数据返回一个集合（一行数据为一个对象，文本较大时不推荐使用）
	 * @param lines
	 * @return	
	 * @throws DataParseException
	 * @author: xue.zhang
	 * @date 2018年2月12日下午4:09:44
	 */
	public abstract List<T> parseList(List<String> lines) throws DataParseException;
	
	/**
	 * @Title: 解析多行数据返回一个集合（一行数据为一个集合，文本较大时不推荐使用）	
	 * @param lines
	 * @return	
	 * @throws DataParseException
	 * @author: xue.zhang
	 * @date 2018年2月12日下午4:09:44
	 */
	public abstract List<List<T>> parseListForArrayInterval(List<String> lines) throws DataParseException;
	
	/* ***********************  2. common method    *********************************************/
	/**
	 * @Title: 一行数据切割后column的数量,默认是0，不校验
	 * @param dataConfig
	 * @param length
	 * @return
	 * @Description: 
	 * @date: 2017年11月18日下午4:34:14
	 */
	public boolean checkedLineDataLength(DataConfig dataConfig, int length) {
		int lineDataLength = dataConfig.lineDataLength();
		return (lineDataLength == 0) ? 
				true : lineDataLength == length;
	}
	
	/**
	 * @Title: 校验是否可以为空，默认是false，不能为空（校验顺序2）
	 * @param columnConfig
	 * @param column
	 * @return
	 * @date: 2017年11月18日下午4:09:05
	 */
	public boolean checkedIsNull(ColumnConfig columnConfig, String column){
		boolean isNull = columnConfig.isNull();
		String defaultValue = columnConfig.defaultValue();//默认值
		if(!isNull) {//不允许为空
			boolean isNullAndEmpty = column == null || column.length() == 0;
			if(isNullAndEmpty){//字段真的是空的
				if(defaultValue != null && defaultValue.length() > 0) {
					column = defaultValue;
				} else {
					return false;
				}
			}
			return true;
		} else {
			if(defaultValue != null && defaultValue.length() > 0) {
				column = defaultValue;
			}
			return true;
		}
	}
	
	/**
	 * @Title: 校验字符串最大长度，默认是0，不检验长度（校验顺序3）
	 * @param columnConfig
	 * @param column
	 * @return
	 * @date: 2017年11月18日下午4:09:12
	 */
	public boolean checkedMaxLength(ColumnConfig columnConfig, String column) {
		int maxLength = columnConfig.maxLength();
		return (maxLength == 0) ? 
				true : column.length() <= maxLength;
	}
	
	/**
	 * @Title: 获得配置好的文件编码
	 * @return
	 * @date: 2018年2月12日下午8:57:03
	 */
	public String charsetName(){
		return this.clazz.getAnnotation(DataConfig.class).charset();
	}
	
	/**
	 * @Title: 校验解析器模板类中字段
	 * @return
	 * @date: 2018年2月12日下午8:57:03
	 */
	public boolean checkedFieldsConfig(){
		Field[] declaredFields = clazz.getDeclaredFields();//获得字段的注解信息
		boolean isConfig = false;//是否有字段的配置
		for (Field field : declaredFields) {
			ColumnConfig columnConfig = field.getAnnotation(ColumnConfig.class);
			if(columnConfig != null) {
				logger.info("校验【{}】 字段【{}】 注解配置【{}】", clazz, field, columnConfig);
				isConfig = true;
			}
		}
		return isConfig;
	}
	
	/* ***********************  3. getter, setter *********************************************/
	public Class<T> getClazz() {
		return clazz;
	}

	public void setClazz(Class<T> clazz) {
		this.clazz = clazz;
	}

	public DataConfig getDataConfig() {
		return dataConfig;
	}

	public void setDataConfig(DataConfig dataConfig) {
		this.dataConfig = dataConfig;
	}
}
